package com.meta.platform.sms.service.invoke.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.github.pagehelper.util.StringUtil;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.meta.framework.util.BeanUtil;
import com.meta.platform.sms.config.AliSmsPushConfig;
import com.meta.platform.sms.constants.SmsChannel;
import com.meta.platform.sms.domain.SmsConfig;
import com.meta.platform.sms.request.InvokeThirdSmsParam;
import com.meta.platform.sms.request.SendSmsParam;
import com.meta.platform.sms.service.invoke.InvokeThirdSmsService;
import com.meta.platform.sms.utils.PhoneUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import java.util.*;

@Service("aliSms")
@Slf4j
public class AliSmsInvokeServiceImpl implements InvokeThirdSmsService {

    static IAcsClient acsClient = null;

    static IAcsClient getClient() {
        if (acsClient == null) {
            IClientProfile profile = DefaultProfile.getProfile(AliSmsPushConfig.endPoint, AliSmsPushConfig.accessKey,
                    AliSmsPushConfig.secret);
            try {
                DefaultProfile.addEndpoint(AliSmsPushConfig.endPoint, AliSmsPushConfig.endPoint, AliSmsPushConfig.product, AliSmsPushConfig.domain);
            } catch (ClientException e) {
                log.error("Exception init client", e);
            }
            acsClient = new DefaultAcsClient(profile);
        }
        return acsClient;
    }

    @Override
    public String outerSmsChannelName() {
        return SmsChannel.ALI.channel;
    }

    @Override
    public InvokeThirdSmsParam generateInvokeParam(SmsConfig smsConfig, SendSmsParam originalParam) {
        InvokeThirdSmsParam result = new InvokeThirdSmsParam();
        BeanUtil.copyProperties(smsConfig, result);
        result.setMobiles(originalParam.getMobiles());
        result.setNativeCode(originalParam.getNativeCode());
        result.setBizId(UUID.randomUUID().toString());
        String smsParams = originalParam.getSmsParams();
        result.setOriginalSmsParam(smsParams);
        String outerSmsTemplate = smsConfig.getOuterSmsTemplate();
        if (Strings.isNullOrEmpty(smsParams)) {
            result.setFinalSmsContent(smsParams);
            return result;
        }
        JSONObject object = JSON.parseObject(smsParams);
        Set<String> jsonKeySets = object.keySet();
        Map<String, Object> params = new HashMap<>();
        for (String key : jsonKeySets) {
            params.put(key, object.get(key));
        }

        boolean flag = true;
        int count = 0;
        while (flag && count < 5) { //最多5个变量替换
            count++;
            int startIndex = outerSmsTemplate.indexOf("${");
            if (startIndex > -1) {
                int endIndex = outerSmsTemplate.indexOf("}");
                String currentParamName = outerSmsTemplate.substring(startIndex + 2, endIndex);
                String replaceContext = "${" + currentParamName + "}";
                outerSmsTemplate = outerSmsTemplate.replace(replaceContext, params.get(currentParamName).toString());

            } else {
                flag = false;
            }
        }
        result.setFinalSmsContent(outerSmsTemplate);
        return result;
    }

    private String getPhones(String nativeCode, Set<String> phones) {
        if (!Strings.isNullOrEmpty(nativeCode) && CollectionUtils.isNotEmpty(phones) && !PhoneUtils.getLocal().equals(nativeCode)) {
            log.info("阿里短信通道转换为国际号码格式 {} 区号 {}", Joiner.on(",").join(phones), nativeCode);
            Set<String> newPhones = Sets.newHashSet();
            phones.forEach(phone -> {
                        newPhones.add("00" + nativeCode + phone);
                    }
            );
            return Joiner.on(",").join(newPhones);
        }
        return Joiner.on(",").join(phones);
    }

    @Override
    public Boolean invokeThirdSmsService(InvokeThirdSmsParam invokeThirdSmsParam) {
        if (StringUtil.isEmpty(AliSmsPushConfig.endPoint)) {
            log.info("阿里云地址配置为空 ");
            return false;
        }

        try {
            SendSmsRequest request = new SendSmsRequest();
            //使用post提交
            request.setMethod(MethodType.POST);
            //必填:待发送手机号。支持以逗号分隔的形式进行批量调用，批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式
            request.setPhoneNumbers(getPhones(invokeThirdSmsParam.getNativeCode(), new HashSet<>(invokeThirdSmsParam.getMobiles())));
            //必填:短信签名-可在短信控制台中找到
            request.setSignName(invokeThirdSmsParam.getSignName());
            //必填:短信模板-可在短信控制台中找到
            request.setTemplateCode(invokeThirdSmsParam.getOuterSmsTemplateCode());
            //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
            //友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败
            request.setTemplateParam(invokeThirdSmsParam.getOriginalSmsParam());

            SendSmsResponse sendSmsResponse = getClient().getAcsResponse(request);
            if (sendSmsResponse.getCode() != null) {
                if (sendSmsResponse.getCode().equals("OK")) {
                    log.info("send aliyun success send text is {} successfully", JSON.toJSONString(invokeThirdSmsParam));
                    return true;
                } else {
                    log.info("send aliyun success send text is {} failed ,fail code is {}", JSON.toJSONString(invokeThirdSmsParam), sendSmsResponse.getCode());
                    return false;
                }

            }
        } catch (Exception e) {
            log.error("aliyun sms occor exception ", e);
        }
        return false;
    }
}
